/* * Copyright (C) 2012 Stichting Akvo (Akvo Foundation) * * This file is part of Akvo FLOW. * * Akvo FLOW is free software: you can redistribute it and modify it under the terms of * the GNU Affero General Public License (AGPL) as published by the Free Software Foundation, * either version 3 of the License or any later version. * * Akvo FLOW is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License included below for more details. * * The full license text can also be seen at <http://www.gnu.org/licenses/agpl.html>. */ package org.waterforpeople.mapping.app.web.rest; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.inject.Inject; import org.springframework.beans.BeanUtils; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.waterforpeople.mapping.app.util.DtoMarshaller; import org.waterforpeople.mapping.app.web.rest.dto.RestStatusDto; import org.waterforpeople.mapping.app.web.rest.dto.SurveyAssignmentDto; import org.waterforpeople.mapping.app.web.rest.dto.SurveyAssignmentPayload; import org.waterforpeople.mapping.domain.SurveyAssignment; import com.gallatinsystems.common.Constants; import com.gallatinsystems.device.dao.DeviceDAO; import com.gallatinsystems.device.domain.Device; import com.gallatinsystems.device.domain.DeviceSurveyJobQueue; import com.gallatinsystems.framework.analytics.summarization.DataSummarizationRequest; import com.gallatinsystems.framework.domain.DataChangeRecord; import com.gallatinsystems.survey.dao.DeviceSurveyJobQueueDAO; import com.gallatinsystems.survey.dao.SurveyAssignmentDAO; import com.gallatinsystems.survey.dao.SurveyDAO; import com.gallatinsystems.survey.domain.Survey; import com.google.appengine.api.taskqueue.Queue; import com.google.appengine.api.taskqueue.QueueFactory; import com.google.appengine.api.taskqueue.TaskOptions; @Controller @RequestMapping("/survey_assignments") public class SurveyAssignmentRestService { @Inject SurveyAssignmentDAO surveyAssignmentDao; private DeviceDAO deviceDao; private SurveyDAO surveyDao; private DeviceSurveyJobQueueDAO deviceSurveyJobQueueDAO; @RequestMapping(method = RequestMethod.GET, value = "") @ResponseBody public Map<String, List<SurveyAssignmentDto>> listAll() { final HashMap<String, List<SurveyAssignmentDto>> response = new HashMap<String, List<SurveyAssignmentDto>>(); final List<SurveyAssignmentDto> results = new ArrayList<SurveyAssignmentDto>(); for (SurveyAssignment sa : surveyAssignmentDao .list(Constants.ALL_RESULTS)) { results.add(marshallToDto(sa)); } response.put("survey_assignments", results); return response; } @RequestMapping(method = RequestMethod.GET, value = "/{id}") @ResponseBody public Map<String, SurveyAssignmentDto> getById(@PathVariable("id") Long id) { final HashMap<String, SurveyAssignmentDto> response = new HashMap<String, SurveyAssignmentDto>(); final SurveyAssignment sa = surveyAssignmentDao.getByKey(id); if (sa == null) { throw new HttpMessageNotReadableException( "Survey Assignment with id: " + id + " not found"); } response.put("survey_assignment", marshallToDto(sa)); return response; } @RequestMapping(method = RequestMethod.DELETE, value = "/{id}") @ResponseBody public Map<String, RestStatusDto> deleteById(@PathVariable("id") Long id) { final HashMap<String, RestStatusDto> response = new HashMap<String, RestStatusDto>(); final SurveyAssignment sa = surveyAssignmentDao.getByKey(id); DeviceSurveyJobQueueDAO deviceSurveysDao = new DeviceSurveyJobQueueDAO(); final List<DeviceSurveyJobQueue> deviceSurveys = deviceSurveysDao.listJobByAssignment(id); RestStatusDto statusDto = new RestStatusDto(); statusDto.setStatus("failed"); if (sa != null && deviceSurveys != null) { surveyAssignmentDao.delete(sa); deviceSurveysDao.delete(deviceSurveys); statusDto.setStatus("ok"); } response.put("meta", statusDto); return response; } @RequestMapping(method = RequestMethod.PUT, value = "/{id}") @ResponseBody public Map<String, SurveyAssignmentDto> updateSurveyAssignment( @PathVariable("id") Long id, @RequestBody SurveyAssignmentPayload payload) { final SurveyAssignmentDto dto = payload.getSurvey_assignment(); if (!id.equals(dto.getKeyId())) { throw new HttpMessageNotReadableException("Ids don't match: " + id + " <> " + dto.getKeyId()); } final SurveyAssignment sa = surveyAssignmentDao .getByKey(dto.getKeyId()); final HashMap<String, SurveyAssignmentDto> response = new HashMap<String, SurveyAssignmentDto>(); if (sa == null) { throw new HttpMessageNotReadableException( "Survey Assignment with id: " + dto.getKeyId() + " not found"); } final SurveyAssignment oldAssignment = new SurveyAssignment(); BeanUtils.copyProperties(sa, oldAssignment); BeanUtils.copyProperties(marshallToDomain(dto), sa); surveyAssignmentDao.save(sa); generateDeviceJobQueueItems(sa, oldAssignment); response.put("survey_assignment", marshallToDto(sa)); return response; } @RequestMapping(method = RequestMethod.POST, value = "") @ResponseBody public Map<String, SurveyAssignmentDto> newSurveyAssignment( @RequestBody SurveyAssignmentPayload payload) { final SurveyAssignmentDto dto = payload.getSurvey_assignment(); final SurveyAssignment sa = new SurveyAssignment(); final HashMap<String, SurveyAssignmentDto> response = new HashMap<String, SurveyAssignmentDto>(); BeanUtils.copyProperties(marshallToDomain(dto), sa); surveyAssignmentDao.save(sa); generateDeviceJobQueueItems(sa, null); response.put("survey_assignment", marshallToDto(sa)); return response; } private SurveyAssignmentDto marshallToDto(SurveyAssignment sa) { final SurveyAssignmentDto dto = new SurveyAssignmentDto(); DtoMarshaller.copyToDto(sa, dto); dto.setDevices(sa.getDeviceIds()); dto.setSurveys(sa.getSurveyIds()); return dto; } private SurveyAssignment marshallToDomain(SurveyAssignmentDto dto) { final SurveyAssignment sa = new SurveyAssignment(); DtoMarshaller.copyToCanonical(sa, dto); sa.setDeviceIds(dto.getDevices()); sa.setSurveyIds(dto.getSurveys()); return sa; } /** * creates and saves DeviceSurveyJobQueue objects for each device/survey pair in the assignment. * If this takes too long to do, may need to make it async * * @param assignment */ private void generateDeviceJobQueueItems(SurveyAssignment assignment, SurveyAssignment oldAssignment) { List<Long> surveyIdsToSave = new ArrayList<Long>( assignment.getSurveyIds()); List<Long> deviceIdsToSave = new ArrayList<Long>( assignment.getDeviceIds()); List<Long> surveyIdsToDelete = new ArrayList<Long>(); List<Long> deviceIdsToDelete = new ArrayList<Long>(); surveyAssignmentDao = new SurveyAssignmentDAO(); deviceDao = new DeviceDAO(); surveyDao = new SurveyDAO(); deviceSurveyJobQueueDAO = new DeviceSurveyJobQueueDAO(); if (oldAssignment != null) { if (oldAssignment.getSurveyIds() != null) { surveyIdsToSave.removeAll(oldAssignment.getSurveyIds()); surveyIdsToDelete = new ArrayList<Long>( oldAssignment.getSurveyIds()); surveyIdsToDelete.removeAll(assignment.getSurveyIds()); } if (oldAssignment.getDeviceIds() != null) { deviceIdsToSave.removeAll(oldAssignment.getDeviceIds()); deviceIdsToDelete = new ArrayList<Long>( oldAssignment.getDeviceIds()); deviceIdsToDelete.removeAll(assignment.getDeviceIds()); } } List<DeviceSurveyJobQueue> queueList = new ArrayList<DeviceSurveyJobQueue>(); Map<Long, Survey> surveyMap = new HashMap<Long, Survey>(); Map<Long, Device> deviceMap = new HashMap<Long, Device>(); if (deviceIdsToSave != null) { // for each new device, we need to save a record for ALL survey IDs // in the assignment for (Long id : deviceIdsToSave) { Device d = deviceMap.get(id); if (d == null) { d = deviceDao.getByKey(id); deviceMap.put(d.getKey().getId(), d); } for (Long sId : assignment.getSurveyIds()) { Survey survey = surveyMap.get(sId); if (survey == null) { survey = surveyDao.getByKey(sId); surveyMap.put(sId, survey); } queueList.add(constructQueueObject(d, survey, assignment)); } } } // if we added any surveys, we need to save a record for ALL the devices // BUT we don't need to process the items that we already saved above if (surveyIdsToSave != null) { for (Long sId : surveyIdsToSave) { Survey survey = surveyMap.get(sId); if (survey == null) { survey = surveyDao.getByKey(sId); surveyMap.put(sId, survey); } for (Long id : assignment.getDeviceIds()) { // only proceed if we haven't already saved the record above if (!deviceIdsToSave.contains(id)) { Device d = deviceMap.get(id); if (d == null) { d = deviceDao.getByKey(id); deviceMap.put(d.getKey().getId(), d); } queueList.add(constructQueueObject(d, survey, assignment)); } } } } if (queueList.size() > 0) { deviceSurveyJobQueueDAO.save(queueList); } if (deviceIdsToDelete.size() > 0 || surveyIdsToDelete.size() > 0) { StringBuilder builder = new StringBuilder("d"); for (int i = 0; i < deviceIdsToDelete.size(); i++) { if (i > 0) { builder.append("xx"); } Device d = deviceMap.get(deviceIdsToDelete.get(i)); if (d == null) { d = deviceDao.getByKey(deviceIdsToDelete.get(i)); deviceMap.put(d.getKey().getId(), d); } builder.append(d.getPhoneNumber()); } builder.append("s"); for (int i = 0; i < surveyIdsToDelete.size(); i++) { if (i > 0) { builder.append("xx"); } builder.append(surveyIdsToDelete.get(i).toString()); } DataChangeRecord change = new DataChangeRecord( SurveyAssignment.class.getName(), assignment.getKey() .getId() + "", builder.toString(), "n/"); Queue queue = QueueFactory.getQueue("dataUpdate"); queue.add(TaskOptions.Builder .withUrl("/app_worker/dataupdate") .param(DataSummarizationRequest.OBJECT_KEY, assignment.getKey().getId() + "") .param(DataSummarizationRequest.OBJECT_TYPE, "DeviceSurveyJobQueueChange") .param(DataSummarizationRequest.VALUE_KEY, change.packString())); } } private DeviceSurveyJobQueue constructQueueObject(Device d, Survey survey, SurveyAssignment assignment) { DeviceSurveyJobQueue queueItem = new DeviceSurveyJobQueue(); queueItem.setDevicePhoneNumber(d.getPhoneNumber()); queueItem.setEffectiveStartDate(assignment.getStartDate()); queueItem.setEffectiveEndDate(assignment.getEndDate()); queueItem.setSurveyID(survey.getKey().getId()); queueItem.setName(survey.getName()); queueItem.setLanguage(assignment.getLanguage()); queueItem.setAssignmentId(assignment.getKey().getId()); queueItem .setSurveyDistributionStatus(DeviceSurveyJobQueue.DistributionStatus.UNSENT); queueItem.setImei(d.getEsn()); queueItem.setAndroidId(d.getAndroidId()); return queueItem; } }